package org.fpp.proxy;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author bigbird-0101
 * @date 2024-06-20 22:52
 */
public class DynamicProxy2 {

    public static void main(String[] args) {
        WanNengHuangNiu wanNengHuangNiu = new WanNengHuangNiu(MaiPiao.class,"System.out.println(\"动态代码\");");
        MaiPiao proxyObj = (MaiPiao) wanNengHuangNiu.getProxyObj();
        proxyObj.maiPiao();

        WanNengHuangNiu wanNengHuangNiuLeiJun = new WanNengHuangNiu(MaiShouJi.class,"System.out.println(\"雷军卖手机\");");
        MaiShouJi maiShouJi = (MaiShouJi) wanNengHuangNiuLeiJun.getProxyObj();
        maiShouJi.maiShouJi();
    }

    public static class WanNengHuangNiu{

        private Object proxyObj;

        public WanNengHuangNiu(Class<?> clazz,String dynamicCode) {
            String s = buildClassString(clazz,dynamicCode);
            String className = clazz.getSimpleName() + "Proxy";
            final Map<String, byte[]> inMemoryClasses = new HashMap<>();
            CodeCompilerUtil.compileCodeFromString(className, s,inMemoryClasses);
            //将文件
            MyClassLoader myClassLoader=new MyClassLoader();
            inMemoryClasses.forEach(myClassLoader::loadStringCode);
            Class<?> aClass;
            try {
                aClass = myClassLoader.loadClass(className);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            try {
                proxyObj= aClass.getConstructor().newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public Object getProxyObj() {
            return proxyObj;
        }

        public String buildClassString(Class<?> clazz, String dynamicCode){
            String interfaceName = clazz.getSimpleName();
            StringBuilder stringBuilder=new StringBuilder();
            String replace = clazz.getName().replaceAll("\\$", ".");
            stringBuilder.append("import ").append(replace).append(";\n");
            stringBuilder.append("public class ").append(clazz.getSimpleName()).append("Proxy").append(" implements ").append(interfaceName)
                    .append("{").append("\n");
            //拼接被代理接口的作为代理类的属性
            stringBuilder.append("  private ").append(interfaceName).append(" proxyobj1;\n");
            //拼接代理类的构造函数
            stringBuilder.append("  public ").append(clazz.getSimpleName()).append("Proxy() {").append("\n");
            stringBuilder.append("    this.proxyobj1 = new ").append(interfaceName).append("(){").append("\n");
            //拼接实现的方法
            Method[] methods = clazz.getMethods();
            for (Method method:methods){
                stringBuilder.append("          public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append("(){").append("\n");
                stringBuilder.append("  System.out.println(\" 我是代理哈哈哈\");");
                stringBuilder.append(dynamicCode);
                stringBuilder.append("          }\n");
            }
            stringBuilder.append("    };\n");
            stringBuilder.append("  }\n");


            //拼接代理类 实现接口方法并调用被代理类的方法

            for (Method method:methods){
                stringBuilder.append("  public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append("(){").append("\n");
                stringBuilder.append("      proxyobj1.").append(method.getName()).append("();").append("\n");
                stringBuilder.append("  }\n");
            }

            stringBuilder.append("}\n");
            System.out.println(stringBuilder);
            return stringBuilder.toString();
        }
    }

    public static class MyClassLoader extends ClassLoader {

        public Class<?> loadStringCode(String className, byte[] bytes){
            Class<?> clazz = defineClass(className,bytes,0,bytes.length);
            return clazz;
        }
    }

    public static class MaiPiaoProxy implements MaiPiao {
        private MaiPiao liangjingRu;

        public MaiPiaoProxy() {
            liangjingRu = new MaiPiao() {
                @Override
                public void maiPiao() {

                }
            };
        }

        @Override
        public void maiPiao(){
            liangjingRu.maiPiao();
        }
    }

    public interface MaiPiao{
        void maiPiao();
    }

    public static class MaiShouJiProxy implements MaiShouJi {
        private MaiShouJi maiShouJi;

        public MaiShouJiProxy() {
            maiShouJi = new MaiShouJi() {
                @Override
                public void maiShouJi() {

                }
            };
        }

        @Override
        public void maiShouJi() {
            maiShouJi.maiShouJi();
        }
    }

    public interface MaiShouJi{
        void maiShouJi();
    }
}
